#include "game_http.h"
#include "game_string.h"
#include <event2/keyvalq_struct.h>
#include <event2/buffer.h>

using namespace CGame::Httpd;





void __evhttpd_parse_query_str(httpd_parameters_t &dest, const char *str)
{
  evkeyvalq params;

  evhttp_parse_query_str(str, &params);

  for (struct evkeyval *kv = params.tqh_first; kv != NULL; kv = kv->next.tqe_next)
  {
    dest.insert(std::make_pair(kv->key, kv->value));
  }
}


HttpdRequest_t* Request::getRequest(){
  return _request;
}

Request::Method Request::getMethod(){
  return _mothod;
}

Request::~Request(){}

Request::Method Request::__evhttp_get_method(HttpdRequest_t *request)
{
  switch (evhttp_request_get_command(request))
  {
  case EVHTTP_REQ_POST:
    return Request::Method::POST;
  case EVHTTP_REQ_HEAD:
    return Request::Method::HEAD;
  case EVHTTP_REQ_PUT:
    return Request::Method::PUT;
  case EVHTTP_REQ_DELETE:
    return Request::Method::DELETE;
  case EVHTTP_REQ_OPTIONS:
    return Request::Method::OPTIONS;

  default:
    return Request::Method::GET;
  };
}

Request::Request(HttpdRequest_t *request)
{
  _request = request;
  _mothod = __evhttp_get_method(request);
  _evhttp_uri = evhttp_request_get_evhttp_uri(request);
}

const char* Request::getHeader(const char *name)
{
  return evhttp_find_header(_request->input_headers, name);
}

INT32 Request::getInt32Header(const char *name)
{
  const char *str = getHeader(name);

  if (NULL != str)
  {
    return CGameValue::_String2Value<INT32>(str);
  }

  return 0;
}

const char* Request::getQueryString() const
{
  return evhttp_uri_get_query(_evhttp_uri);
}

const char* Request::getRequestURL()
{
  return evhttp_uri_get_path(_evhttp_uri);
}

const char* Request::getHost() const
{
  return evhttp_request_get_host(_request);
}

size_t Request::getContentLength() const
{

  return CGameValue::_String2Value<size_t>(evhttp_find_header(_request->input_headers, "Content-Length"));
}

const char *Request::getContetType() const
{
  return evhttp_find_header(_request->input_headers, "Content-Type");
}

void Request::mark(int idx)
{
  _mark = _mark | (1 << Mark::Cookie);
}

BOOL Request::isMark(int idx)
{
  // _mark = _mark | (1 << Mark::Cookie);

  if (0 != (_mark & (1 << idx)))
    return TRUE;
  else
    return FALSE;
}

void Request::cookies()
{
  if (!isMark(Mark::Cookie))
  {
    const char* c = getHeader("Cookie");
    if(NULL != c){
      std::string str = c;
      // __log("cookies is %s\n",str.c_str());

      BOOL s = TRUE;
      BOOL b = FALSE;
      BOOL e = FALSE;
      std::string name;
      std::string val;
      for (size_t i = 0; i < str.size(); i++)
      {
        if (!s)
        {
          if (32 == str.at(i))
            continue;
          else
          {
            s = TRUE;
            name.append(1, str.at(i));
          }
        }
        else if (!b)
        {
          if (61 == str.at(i))
          {
            b = TRUE;
            continue;
          }
          name.append(1, str.at(i));
        }
        else if (b)
        {
          if (59 == str.at(i))
          {
            e = TRUE;
          }
          else if (i == (str.size() - 1))
          {
            val.append(1, str.at(i));
            e = TRUE;
          }

          if (e)
          {
            s = FALSE;
            b = FALSE;
            e = FALSE;
            _cookies.insert(std::make_pair(name, val));
            name.clear();
            val.clear();
          }
          else
            val.append(1, str.at(i));
        }
      }
    }

    mark(Mark::Cookie);
  }
}

void Request::parameters()
{
  if (0 == (_mark & (1 << Mark::Parameter)))
  {

    const char *q = getQueryString();
    __evhttpd_parse_query_str(_params, q);

    const char* ct = getContetType();

    if (NULL != ct && !strcasecmp(MediaType::APPLICATION_FORM_URLENCODED_VALUE, getContetType()))
    {
      evbuffer *inbuf = evhttp_request_get_input_buffer(_request);

      int len = evbuffer_get_length(inbuf);

      char *data = (char *)malloc(len + 1);

      data[len] = '\0';

      evbuffer_copyout(inbuf, data, len);
      __evhttpd_parse_query_str(_params, data);

      free(data);
    }

    _mark = _mark | (1 << Mark::Parameter);
  }
}

const char *Request::getCookie(const char *name)
{
  cookies();
  httpd_cookies_t::iterator itr = _cookies.find(name);
  if (itr != _cookies.end())
  {
    return itr->second.c_str();
  }

  return NULL;
}

const httpd_parameters_t& Request::getParameterMap(){
  parameters();
  return _params;
}


const char* Request::getParameter(const char *name)
{

  parameters();
  httpd_parameters_t::iterator itr = _params.find(name);

  if (itr != _params.end())
  {
    return itr->second.c_str();
  }

  return NULL;
}

const char* Request::getScheme() const
{
  return evhttp_uri_get_scheme(_evhttp_uri);
}

int Request::getPort()
{
  return evhttp_uri_get_port(_evhttp_uri);
}
